﻿using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Folding;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Shapes;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor
{
    /// <summary>
    /// 此类用以定义编辑器的折叠区。
    /// </summary>
    class CustomFoldingStrategyForPython : AbstractFoldingStrategy
    {
        private ICSharpCode.AvalonEdit.TextEditor edit;
        /// <summary>
        /// 要应用折叠功能的编辑器。
        /// </summary>
        public ICSharpCode.AvalonEdit.TextEditor Edit { get { return this.edit; } }

        /// <summary>
        /// [构造方法]创建一个新的折叠区。
        /// </summary>
        public CustomFoldingStrategyForPython(ICSharpCode.AvalonEdit.TextEditor edit)
        {
            this.edit = edit;
        }

        /// <summary>
        /// 为特定文档创建 NewFolding 对象集。
        /// </summary>
        public override IEnumerable<NewFolding> CreateNewFoldings(TextDocument document, out int firstErrorOffset)
        {
            firstErrorOffset = -1;
            return CreateNewFoldings(document);
        }

        /// <summary>
        /// 为特定文档创建 NewFolding 对象集。
        /// </summary>
        public IEnumerable<NewFolding> CreateNewFoldings(ITextSource document)
        {
            List<NewFolding> newFoldings = new List<NewFolding>();

            var trimChars = new char[] { ' ', '　', '\t', };

            var regAlt = new Regex(@"(?<=([aA][lL][tT][ \t]{0,}[=][ \t]{0,}['""])).*?(?=(['""]))");

            #region Python 源码

            int currentLineOffset = -1;
            int currentLineEndOffset = -1;
            List<LineOffsetInfo> infoList = new List<LineOffsetInfo>();

            for (int i = 1; i <= edit.LineCount; i++)
            {
                var line = edit.Document.GetLineByNumber(i);
                currentLineOffset = line.Offset;
                currentLineEndOffset = line.EndOffset;
                string lineText = edit.Document.GetText(line.Offset, line.Length);

                if (string.IsNullOrEmpty(lineText)) continue;  // 空行忽略

                int curIndentLevel = GetCodeIndentLevel(lineText);

                var curLineOffsetInfo = new LineOffsetInfo()
                {
                    Offset = currentLineOffset,
                    EndOffset = currentLineEndOffset,
                    Length = line.Length,
                    IndentLevel = curIndentLevel,
                    LineText = lineText,
                    Folding = new NewFolding()
                    {
                        Name = lineText,
                        StartOffset = currentLineOffset,
                        EndOffset = currentLineEndOffset,  // 这里一定是大于的
                    }
                };

                infoList.Add(curLineOffsetInfo);
            }

            if (infoList.Count >= 1)
            {
                // 加上一个虚拟的尾行
                infoList.Add(new LineOffsetInfo()
                {
                    Offset = currentLineEndOffset + 2,
                    EndOffset = currentLineEndOffset + 2,
                    Length = 0,
                    IndentLevel = 0,
                    LineText = "",
                    Folding = null
                });

                // 用两层循环来搞定
                for (int i = 0; i < infoList.Count; i++)
                {
                    var thisInfo = infoList[i];
                    // 找到父节点，设置父节点的 EndOffset 为当前行尾
                    SetLowerLevelLineFoldingEndOffsets(ref infoList, thisInfo, i - 1);
                }

                for (int i = 0; i < infoList.Count - 1; i++)
                {
                    // 最后一个虚拟的不要
                    var info = infoList[i];
                    if (info.Folding == null) continue;
                    if (info.Folding.EndOffset <= info.EndOffset) continue;

                    if (i <= infoList.Count - 2)
                    {
                        if (infoList[i + 1].IndentLevel <= info.IndentLevel) continue;
                    }

                    newFoldings.Add(info.Folding);
                }
            }

            #endregion

            newFoldings.Sort((a, b) => a.StartOffset.CompareTo(b.StartOffset));
            return newFoldings;
        }

        private void SetLowerLevelLineFoldingEndOffsets(ref List<LineOffsetInfo> infoList, LineOffsetInfo curLineInfo, int i)
        {
            if (infoList == null || infoList.Count <= 0 || curLineInfo == null) return;
            if (i < 0 || i >= infoList.Count) return;

            var level = curLineInfo.IndentLevel;
            for (int j = i; j >= 0; j--)
            {
                var info = infoList[j];
                if (info.IndentLevel < level)
                {
                    info.Folding.EndOffset = curLineInfo.EndOffset;
                    level = info.IndentLevel;
                }
            }
        }

        /// <summary>
        /// 判断 Python 脚本行的缩进层级（每四个半角空格为一级，最低0级）。
        /// </summary>
        /// <param name="line">代码行文本。</param>
        /// <returns>返回缩进级别数值。</returns>
        private int GetCodeIndentLevel(string line)
        {
            if (string.IsNullOrEmpty(line)) return 0;

            var regex = new Regex(@"^[\t ]*");
            var match = regex.Match(line);
            if (match.Success == false || match.Length <= 0) return 0;

            var header = match.Value.Replace("\t", "    ").Replace("    ", "a");
            return header.Length;
        }
    }

    public class LineOffsetInfo
    {
        public int Offset { get; set; }
        public int EndOffset { get; set; }
        public int Length { get; set; }
        public int IndentLevel { get; set; }
        public string LineText { get; set; }
        public NewFolding Folding { get; set; }
    }

}
